package com.baijia.services.impl;

import com.baijia.authentication.principal.Service;
import com.baijia.dao.po.AuthorizeService;
import com.baijia.services.AuthorizeServiceManager;
import com.baijia.services.RegisteredService;
import com.baijia.services.ServicesManager;

import com.alibaba.fastjson.JSONObject;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;

import java.util.Collection;
import java.util.Collections;
import java.util.TreeSet;
import java.util.concurrent.ConcurrentHashMap;

/**
 * @title ServicesManagerImpl
 * @desc 管理注册的service
 * @author caoliang
 * @date 2015年12月4日
 * @version 1.0
 */
@Component
public final class ServicesManagerImpl implements ServicesManager, ApplicationContextAware {

    private final Logger log = LoggerFactory.getLogger(getClass());
    @Autowired
    private AuthorizeServiceManager authorizeServiceManager;

    /**
     * <id,service>
     */
    private ConcurrentHashMap<Integer, RegisteredService> services =
        new ConcurrentHashMap<Integer, RegisteredService>();

    @Override
    public synchronized RegisteredService delete(final int id) {
        final RegisteredService r = findServiceBy(id);
        if (r == null) {
            return null;
        }
        // TODO 当前配置在枚举中，后续可考虑迁移到zk，以便支持热加载
        this.services.remove(id);

        return r;
    }

    @Override
    public RegisteredService findServiceBy(final Service service) {
        // final Collection<RegisteredService> c = convertToTreeSet();
        final Collection<RegisteredService> c = this.services.values();
        log.info(JSONObject.toJSONString(c));
        for (final RegisteredService r : c) {
            if (r.matches(service)) {
                return r;
            }
        }

        return null;
    }

    @Override
    public RegisteredService findServiceBy(final int id) {
        final RegisteredService r = this.services.get(id);
        return r;
        // try {
        // return r == null ? null : r;
        // return r == null ? null : (RegisteredService) r.clone();
        // } catch (final CloneNotSupportedException e) {
        // return r;
        // }
    }

    protected TreeSet<RegisteredService> convertToTreeSet() {
        return new TreeSet<RegisteredService>(this.services.values());
    }

    @Override
    public Collection<RegisteredService> getAllServices() {
        return Collections.unmodifiableCollection(convertToTreeSet());
    }

    @Override
    public boolean matchesExistingService(final Service service) {
        return findServiceBy(service) != null;
    }

    @Override
    public synchronized RegisteredService save(final RegisteredService registeredService) {
        this.services.put(registeredService.getId(), registeredService);
        return registeredService;
    }

    // 3分钟重新加载一次注册服务
    @Scheduled(initialDelay = 3 * 60 * 1000, fixedRate = 3 * 60 * 1000)
    public void reload() {
        log.info("Reloading registered services.");
        load();
    }

    private void load() {
        final ConcurrentHashMap<Integer, RegisteredService> localServices =
            new ConcurrentHashMap<Integer, RegisteredService>();

        for (AuthorizeService service : authorizeServiceManager.getServices()) {
            RegisteredServiceImpl r = new RegisteredServiceImpl();
            r.setId(service.getId());
            r.setServiceId(service.getServiceId());
            r.setAllowDomains(service.getAllowDomainsList());
            r.setName(service.getName());
            r.setLoginAddr(service.getLoginAddr());
            r.setLoginSuccessAddr(service.getLoginSuccessAddr());
            r.setLoginMaxTimes(service.getLoginMaxTimes());
            r.setLoginNoticeTimes(service.getLoginNoticeTimes());
            r.setBanSeconds(service.getBanSeconds());
            localServices.put(r.getId(), r);
        }

        this.services = localServices;
        log.info(String.format("Loaded %s services.", this.services.size()));
    }

    public AuthorizeServiceManager getAuthorizeServiceManager() {

        return authorizeServiceManager;
    }

    public void setAuthorizeServiceManager(AuthorizeServiceManager authorizeServiceManager) {

        this.authorizeServiceManager = authorizeServiceManager;
    }

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        load();
    }
}
